package com.googlecode.classgrep.visitor.annotated;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.EmptyVisitor;

import com.googlecode.classgrep.GrepRobotInternal;
import com.googlecode.classgrep.grep.annotated.ClassGrep;
import com.googlecode.classgrep.info.AnnotationInfo;
import com.googlecode.classgrep.info.ClassInfo;
import com.googlecode.classgrep.info.FieldInfo;
import com.googlecode.classgrep.info.MethodInfo;
import com.googlecode.classgrep.utils.CommonUtils;

public class ClassDefVisitor extends CommonDef  implements ClassVisitor  {

	
    private ClassGrep classGrep;

    protected ClassInfo info;
    
	public ClassDefVisitor(GrepRobotInternal grepClient) {
		super(grepClient);
		this.classGrep = grepClient.getClassGrep();
	}

	public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        if (name.endsWith("package-info")) {
            //info = new PackageInfo(CommonUtils.javaName(name));
        } else {
            ClassInfo classInfo = new ClassInfo(CommonUtils.javaName(name), CommonUtils.javaName(superName));

            for (String interfce : interfaces) {
                classInfo.getInterfaces().add(CommonUtils.javaName(interfce));
            }
            info = classInfo;
            classGrep.getClassInfos().put(classInfo.getName(), classInfo);

            /*if (grepClient.isExtractSuperInterfaces())*/
            extractSuperInterfaces(classInfo);
        }
	}

    private void extractSuperInterfaces(ClassInfo classInfo) {
        String superType = classInfo.getSuperType();

        if (superType != null) {
            ClassInfo base = classGrep.getClassInfos().get(superType);

            if (base == null) {
                //try to load base
                String resource = superType.replace('.', '/') + ".class";
                
                grepClient.readClassDef(resource);
                
                base = classGrep.getClassInfos().get(superType);
            }

            if (base != null) {
                List<String> interfaces = classInfo.getSuperInterfaces();
                interfaces.addAll(base.getSuperInterfaces());
                interfaces.addAll(base.getInterfaces());
            }
        }
    }

	public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
		AnnotationInfo annotationInfo = new AnnotationInfo(desc);
		if(grepClient.getAnnotationCriterion().contains(annotationInfo.getName())){
	        info.getAnnotations().add(annotationInfo);
	        List<ClassInfo> infos = classGrep.getAnnotatedClassMap().get(annotationInfo.getName());
	        if (infos == null) {
	            infos = new ArrayList<ClassInfo>();
	            classGrep.getAnnotatedClassMap().put(annotationInfo.getName(), infos);
	        }
	        infos.add(info);
	        return new AnnotationDefVisitor(grepClient, annotationInfo);
		}else{
			return new EmptyVisitor();
		}
	}

	
	public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
		FieldInfo fieldInfo = new FieldInfo(info, name, desc);
		info.getFields().add(fieldInfo);
		return new FieldDefVisitor(grepClient, fieldInfo);
	}

	
	public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
		MethodInfo methodInfo = new MethodInfo(info, name, desc);
		info.getMethods().add(methodInfo);
		return new MethodDefVisitor(grepClient, methodInfo);
	}
	

	public void visitSource(String source, String debug) {
		
	}

	public void visitOuterClass(String owner, String name, String desc) {
		
	}

	public void visitAttribute(Attribute attr) {
		
	}

	public void visitInnerClass(String name, String outerName, String innerName, int access) {
		
	}

	public void visitEnd() {
		
	}

	
}
